package cn.xo68.boot.webgather.http;

import okhttp3.Call;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.util.concurrent.TimeUnit;

/**
 * 下载回调
 *
 * @author wuyy
 * @date 2018年1月11日下午2:18:49
 */
public class DownloadHttpCallback implements HttpCallback {

    private final static Logger logger = LoggerFactory.getLogger(DownloadHttpCallback.class);

    private String saveFileName = null;
    private String saveDirectory = null;
    private Long fileSize = 0L;
    private Throwable exception = null;
    /**
     * 最大下载速度，0为不限,默认256K
     */
    private long maxRate = 256 * 1024L;

    private long startTime = 0L;
    private volatile long lastTime = 0L;
    private volatile long rate = 0L;

    private volatile long downloadedSize=0L;


    public DownloadHttpCallback(String saveFileName, String saveDirectory) {
        super();
        this.saveFileName = saveFileName;
        this.saveDirectory = saveDirectory;
    }

    public String getSaveFileName() {
        return saveFileName;
    }

    public String getSaveDirectory() {
        return saveDirectory;
    }

    public long getMaxRate() {
        return maxRate;
    }

    public void setMaxRate(long maxRate) {
        this.maxRate = maxRate;
    }

    public Throwable getException() {
        return exception;
    }

    /**
     * 计算每秒下载速度
     */
    private void calculateRate(){
        lastTime =  System.nanoTime();
        long castNanos= lastTime - startTime ;
        if( castNanos == 0L){
            rate = downloadedSize;
        }else {
            rate= downloadedSize*1000*1000*1000 /castNanos;
        }
    }

    @Override
    public void success(Response response, Call call) {
        int len = 0;

        // 储存下载文件的目录
        File directory = new File(saveDirectory);
        if (!directory.exists()) {
            directory.mkdirs();
        }


        ByteBuffer buffer = ByteBuffer.allocate(1024);
        File file = new File(directory, saveFileName);
        startTime = System.nanoTime();

        try (InputStream is= response.body().byteStream();
             ReadableByteChannel rc =Channels.newChannel(is);
             FileOutputStream fos = new FileOutputStream(file);
             FileChannel fc = fos.getChannel();){

            fileSize = response.body().contentLength();
            int progress;



            while ((len = rc.read(buffer)) > 0 ) {
                buffer.flip();
                fc.write(buffer);
                buffer.clear();
                downloadedSize += len;
                if(fileSize>0L){
                    progress = (int) (downloadedSize * 1.0f / fileSize * 100);
                }


                calculateRate();
                while (maxRate>0 && rate > maxRate){
                    if(rate > maxRate * 1.2){
                        logger.debug("当前速度: {} kb", rate/1024);
                    }
                    Thread.sleep(200);
                    calculateRate();
                }

            }
            long castSeconds= TimeUnit.SECONDS.convert(lastTime - startTime, TimeUnit.NANOSECONDS) ;
            logger.debug("文件大小：{}kb,下载费时: {} 秒",downloadedSize/1024, castSeconds);
        } catch (Exception e) {
            this.exception = e;
            logger.error("响应数据流处理异常", e);
        }
    }


    @Override
    public void failure(IOException e, Call call) {
        this.exception = e;
        logger.error("请求数据异常", e);
    }

    @Override
    public boolean hasException() {
        return exception!=null;
    }

}
